
public class Test {
    public static void main(String[] args) throws InterruptedException {
        // 目标线程只要捕获到join()方法抛出的InterruptedException，就说明有其他线程对其调用了interrupt()方法，通常情况下该线程应该立刻结束运行。
        // test_interrupt();
        test_volatile();
    }

    public static void test_interrupt() throws InterruptedException {
        Thread t = new MyThread();
        t.start();
        Thread.sleep(1); // 暂停1毫秒
        t.interrupt(); // 中断t线程
        t.join(); // 等待t线程结束
        System.out.println("end");
        // main线程通过调用t.interrupt()方法中断t线程，但是要注意，interrupt()方法仅仅向t线程发出了“中断请求”，至于t线程是否能立刻响应，要看具体代码。
        // 而t线程的while循环会检测isInterrupted()，所以上述代码能正确响应interrupt()请求，使得自身立刻结束运行run()方法
    }

    public static void test_volatile() throws InterruptedException {
        HelloThread t = new HelloThread();
        t.start();
        Thread.sleep(1); // 暂停1毫秒
        t.running = false; // 将running设置为false，通知线程t停止运行
        t.join(); // 等待t线程结束
        System.out.println("main end");
    }
}

class MyThread extends Thread {
    public void run() {
        int n = 0;
        while (!isInterrupted()) {
            n++;
            System.out.println(n + " hello!");
        }
    }
}

class HelloThread extends Thread {
    // 线程间共享变量需要使用volatile关键字标记，确保每个线程都能读取到更新后的变量值。
    // 为什么要对线程间共享的变量用关键字volatile声明？这涉及到Java的内存模型。在Java虚拟机中，

    // 变量的值保存在主内存中，
    // 但是，当线程访问变量时，它会先获取一个副本，并保存在自己的工作内存中。
    // 如果线程修改了变量的值，虚拟机会在某个时刻把修改后的值回写到主内存，但是，这个时间是不确定的！造成了多线程之间共享的变量不一致。
    // 因此，volatile关键字的目的是告诉虚拟机：
    // 每次访问变量时，总是获取主内存的最新值；
    // 每次修改变量后，立刻回写到主内存。
    // [参考](https://liaoxuefeng.com/books/java/threading/interrupt/index.html)
    public volatile boolean running = true;

    public void run() {
        int n = 0;
        while (running) {

            n++;
            System.out.println(n + " hello!");
        }
        System.out.println("end!");
    }
}